// 现代 JavaScript async/await
// 作者：AI助手
// 最后更新：2024年

/**
 * async/await 是 Promise 的语法糖，让异步代码更易读和维护
 * 特点：
 * 1. async 函数总是返回 Promise
 * 2. await 只能在 async 函数内使用
 * 3. 可以使用 try/catch 进行错误处理
 * 4. 支持顺序和并行执行
 */

// 1. 基本用法
// 1.1 异步函数声明
async function fetchData() {
    return '这是一些数据';
}

// 1.2 使用 async 函数
async function displayData() {
    try {
        const data = await fetchData();
        console.log('获取到的数据:', data);
    } catch (error) {
        console.error('错误:', error);
    }
}

displayData();

// 2. 实际应用示例
// 2.1 模拟 API 调用
const api = {
    async getUser(id) {
        // 模拟网络请求
        await new Promise(resolve => setTimeout(resolve, 1000));
        const users = {
            1: { id: 1, name: '张三', email: 'zhangsan@example.com' },
            2: { id: 2, name: '李四', email: 'lisi@example.com' }
        };
        if (users[id]) return users[id];
        throw new Error('用户不存在');
    },

    async getUserPosts(userId) {
        await new Promise(resolve => setTimeout(resolve, 1000));
        return [
            { id: 1, title: '第一篇文章', content: '内容...' },
            { id: 2, title: '第二篇文章', content: '内容...' }
        ];
    },

    async getPostComments(postId) {
        await new Promise(resolve => setTimeout(resolve, 1000));
        return [
            { id: 1, text: '很好的文章！' },
            { id: 2, text: '学习了！' }
        ];
    }
};

// 2.2 使用 async/await 处理多个异步操作
async function getUserData(userId) {
    try {
        // 按顺序执行异步操作
        const user = await api.getUser(userId);
        const posts = await api.getUserPosts(userId);
        const comments = await api.getPostComments(posts[0].id);

        return {
            user,
            posts,
            comments
        };
    } catch (error) {
        console.error('获取用户数据失败:', error);
        throw error;
    }
}

// 2.3 并行执行异步操作
async function getUserDataParallel(userId) {
    try {
        // 并行执行多个异步操作
        const [user, posts] = await Promise.all([
            api.getUser(userId),
            api.getUserPosts(userId)
        ]);

        // 等待获取第一篇文章的评论
        const comments = await api.getPostComments(posts[0].id);

        return {
            user,
            posts,
            comments
        };
    } catch (error) {
        console.error('获取用户数据失败:', error);
        throw error;
    }
}

// 3. 错误处理模式
// 3.1 使用 try/catch
async function handleErrors() {
    try {
        await api.getUser(999); // 不存在的用户
    } catch (error) {
        console.error('捕获到错误:', error.message);
    }
}

// 3.2 使用 async IIFE（立即执行异步函数）
(async () => {
    try {
        const result = await getUserData(1);
        console.log('用户数据:', result);
    } catch (error) {
        console.error('主程序错误:', error);
    }
})();

// 4. 高级模式
// 4.1 带重试的异步函数
async function fetchWithRetry(fn, maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
        try {
            return await fn();
        } catch (error) {
            if (i === maxRetries - 1) throw error;
            console.log(`重试 ${i + 1}/${maxRetries}`);
            await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
        }
    }
}

// 4.2 带超时的异步函数
async function withTimeout(asyncFn, timeout) {
    const timeoutPromise = new Promise((_, reject) =>
        setTimeout(() => reject(new Error('操作超时')), timeout)
    );
    return Promise.race([asyncFn(), timeoutPromise]);
}

// 4.3 异步函数池
class AsyncPool {
    constructor(maxConcurrent = 3) {
        this.maxConcurrent = maxConcurrent;
        this.running = 0;
        this.queue = [];
    }

    async add(fn) {
        if (this.running >= this.maxConcurrent) {
            // 等待队列中的任务
            await new Promise(resolve => this.queue.push(resolve));
        }

        this.running++;
        try {
            return await fn();
        } finally {
            this.running--;
            if (this.queue.length > 0) {
                const next = this.queue.shift();
                next();
            }
        }
    }
}

// 5. 最佳实践
// ✅ 正确处理错误
async function goodAsyncFunction() {
    try {
        const result = await riskyOperation();
        return result;
    } catch (error) {
        // 处理错误
        console.error(error);
        // 可以选择重新抛出
        throw error;
    }
}

// ✅ 并行处理独立的异步操作
async function efficientAsync() {
    const [result1, result2] = await Promise.all([
        independentOperation1(),
        independentOperation2()
    ]);
}

// ❌ 避免不必要的 await
// async function inefficientAsync() {
//     const result1 = await operation1(); // 如果 operation1 和 operation2 相互独立
//     const result2 = await operation2(); // 应该使用 Promise.all
// }

// ❌ 避免在循环中使用 await
// async function badAsyncLoop() {
//     for (const item of items) {
//         await processItem(item); // 应该使用 Promise.all 和 map
//     }
// }

// 使用示例
async function runExamples() {
    // 1. 基本用法示例
    await handleErrors();

    // 2. 并行vs顺序执行比较
    console.time('顺序执行');
    await getUserData(1);
    console.timeEnd('顺序执行');

    console.time('并行执行');
    await getUserDataParallel(1);
    console.timeEnd('并行执行');

    // 3. 重试示例
    await fetchWithRetry(async () => {
        throw new Error('模拟失败');
    }).catch(error => console.log('重试最终失败:', error.message));

    // 4. 超时示例
    await withTimeout(
        async () => {
            await new Promise(resolve => setTimeout(resolve, 2000));
            return '完成';
        },
        1000
    ).catch(error => console.log('超时错误:', error.message));

    // 5. 异步池示例
    const pool = new AsyncPool(2);
    const tasks = [1, 2, 3, 4, 5].map(i => async () => {
        await new Promise(resolve => setTimeout(resolve, 1000));
        return `任务 ${i} 完成`;
    });

    const results = await Promise.all(
        tasks.map(task => pool.add(task))
    );
    console.log('所有任务完成:', results);
}

runExamples().catch(console.error); 